
// ----------------------------------------------------------------------------
// The ZAstBuildingParser class interface 
//
// Subclasses AstBuildingParser


class ZAstBuildingParser : public AstBuildingParser {
 public:
  ZAstBuildingParser(Handle<Script> script, bool allow_natives_syntax,
                     v8::Extension* extension, ScriptDataImpl* pre_data)
      : AstBuildingParser(script, allow_natives_syntax,
                          extension, pre_data) { 
    //PrintF("++++ new ZAstBuildingParser\n"); 
    scanner().is_zed(true);
  }
  
 protected:
 
  Block* ParseStatements(ZoneStringList* labels, bool* ok);
  Block* ParseStatements(ZoneStringList* labels, Token::Value tokStatement, bool* ok);

  LoopStatement* ParseWhileStatement(ZoneStringList* labels, bool* ok);
  IfStatement* ParseIfStatement(ZoneStringList* labels, bool* ok);
  
  void ExpectSemicolon(bool* ok);
  
  TryStatement* ParseTryStatement(bool* ok);
  Block* WithHelper(Expression* obj,
                    ZoneStringList* labels,
                    bool is_catch_block,
                    bool* ok);
  CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok);
  SwitchStatement* ParseSwitchStatement(ZoneStringList* labels, bool* ok);
  FunctionLiteral* ParseFunctionLiteral(Handle<String> var_name,
                                        int function_token_position,
                                        FunctionLiteralType type,
                                        bool* ok);
  Statement* ParseForStatement(ZoneStringList* labels, bool* ok);
  //Block* ParseBlock(ZoneStringList* labels, bool* ok);
  Statement* ParseWithStatement(ZoneStringList* labels, bool* ok);
};


// ----------------------------------------------------------------------------
// Utility functions

// TODO: HACK. Rewrite when find a better way of passing is_zed to shell and browser.
// is_zed function tests if source file is a 'zed' file by looking at first 5 chars
// 0 1 2 3 4 
// / / z e d  
// note; a file of just 5 chars of '//zed' is not considered a zed file 
// - it contains no code

static const int kIsZedNumChars = 5;

// Called from MakeAST functions.
static bool is_zed(Handle<Script> script) {
    
    Handle<String> source = Handle<String>(String::cast(script->source()));
    int length = source->length();
    //PrintF("is_zed - called from MakeAst - stream->Length() is %i \n", length);
    
    // Only check if at least 6 chars in source
    if (length <= kIsZedNumChars) return false;
    
    // Check if '//zed'
    Object* oslice = source->Slice(0, kIsZedNumChars);
    String* slice = String::cast(oslice);
    Vector<const char> vec_is_zed = CStrVector("//zed");
    return slice->IsEqualTo(vec_is_zed);
}


// Called from PreParse
static bool is_zed(unibrow::CharacterStream* stream) {
  int length = stream->Length();
  //PrintF("is_zed - called from PreParse - stream->Length() is %i \n", length);
  
  // Only check if at least >5 chars in source
  if (length <= kIsZedNumChars) return false;
  
  // Load a vector with the first k chars in file
  Vector<char> vec = Vector<char>::New(kIsZedNumChars);
  for (int i=0; i < kIsZedNumChars; i++) {
      int u = stream->GetNext();
      char c = static_cast<char>(u);
      //PrintF("GetNext %i \n", u);
      //PrintF("GetNext %c \n", c);  
      vec[i] = c;
  }
  stream->Rewind();
  
  // Check if '//zed'    
  // match
  if (vec[0] == '/' && vec[1] == '/' && vec[2] == 'z' && vec[3] == 'e' && vec[4] == 'd')
    return true;
  // no match
  return false;
}


// ----------------------------------------------------------------------------
// The ZAstBuildingParser class implementation.
//
// 


// Z: From ParseBlock
Block* ZAstBuildingParser::ParseStatements(ZoneStringList* labels, bool* ok) {
  // Block ::
  //   '{' Statement* '}'

  // Note that a Block does not introduce a new execution scope!
  // (ECMA-262, 3rd, 12.2)
  //
  // Construct block expecting 16 statements.
  Block* result = NEW(Block(labels, 16, false));
  Target target(this, result);
  //Expect(Token::LBRACE, CHECK_OK);
  while (peek() != Token::END) {
    Statement* stat = ParseStatement(NULL, CHECK_OK);
    if (stat && !stat->IsEmpty()) result->AddStatement(stat);
  }
  //Expect(Token::RBRACE, CHECK_OK);
  return result;
}


// Z: From ParseBlock. Special processing for Statements requiring a 'bail out'.
Block* ZAstBuildingParser::ParseStatements(ZoneStringList* labels, Token::Value tokStatement, bool* ok) {
  // Block ::
  //   '{' Statement* '}'

  // Note that a Block does not introduce a new execution scope!
  // (ECMA-262, 3rd, 12.2)
  //
  // Construct block expecting 16 statements.
  Block* result = NEW(Block(labels, 16, false));
  Target target(this, result);
  //Expect(Token::LBRACE, CHECK_OK);
  while (peek() != Token::END) {
    // Begin bail out
    if (tokStatement == Token::IF && (peek() == Token::ELIF || peek() == Token::ELSE))
      break;
    if (tokStatement == Token::TRY && (peek() == Token::CATCH || peek() == Token::FINALLY))
      break;  
    // End bail out
  
    Statement* stat = ParseStatement(NULL, CHECK_OK);
    if (stat && !stat->IsEmpty()) result->AddStatement(stat);
  }
  //Expect(Token::RBRACE, CHECK_OK);
  return result;
}



LoopStatement* ZAstBuildingParser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
  // WhileStatement ::
  //   'while' '(' Expression ')' Statement

  LoopStatement* loop = NEW(LoopStatement(labels, LoopStatement::WHILE_LOOP));
  Target target(this, loop);

  Expect(Token::WHILE, CHECK_OK);
  Expect(Token::LPAREN, CHECK_OK);
  Expression* cond = ParseExpression(true, CHECK_OK);
  Expect(Token::RPAREN, CHECK_OK);
  //Statement* body = ParseStatement(NULL, CHECK_OK);
  //Statement* body = ParseStatements(NULL, CHECK_OK);
  Statement* body = ParseStatements(NULL,  Token::IF, CHECK_OK);
  
  //Expect(Token::RBRACE, CHECK_OK); // Z end
  Expect(Token::END, ok); // Z: end

  if (loop) loop->Initialize(NULL, cond, NULL, body);
  return loop;
}


void ZAstBuildingParser::ExpectSemicolon(bool* ok) {
  // Check for automatic semicolon insertion according to
  // the rules given in ECMA-262, section 7.9, page 21.
  Token::Value tok = peek();
  if (tok == Token::SEMICOLON) {
    Next();
    return;
  }
  if (scanner_.has_line_terminator_before_next() ||
      // Z: tok == Token::RBRACE ||
      tok == Token::END ||
      tok == Token::EOS) {
    return;
  }
  Expect(Token::SEMICOLON, ok);
}
/*
IfStatement* ZAstBuildingParser::ParseIfStatement(ZoneStringList* labels, bool* ok) {
  // IfStatement ::
  //   'if' '(' Expression ')' Statement ('else' Statement)?

  Expect(Token::IF, CHECK_OK);
  Expect(Token::LPAREN, CHECK_OK);
  Expression* condition = ParseExpression(true, CHECK_OK);
  Expect(Token::RPAREN, CHECK_OK);
  //Z: Statement* then_statement = ParseStatement(labels, CHECK_OK);
  Statement* then_statement = ParseStatements(labels, Token::IF, CHECK_OK);
  Statement* else_statement = NULL;
  if (peek() == Token::ELSE) {
    Next();
    //Z:  else_statement = ParseStatement(labels, CHECK_OK);
    else_statement = ParseStatements(labels, Token::IF, CHECK_OK);
  } else if (!is_pre_parsing_) {
    else_statement = factory()->EmptyStatement();
  }
  ExpectEnd(CHECK_OK); // Z: end
  return NEW(IfStatement(condition, then_statement, else_statement));
}
*/

IfStatement* ZAstBuildingParser::ParseIfStatement(ZoneStringList* labels, bool* ok) {
  // IfStatement ::
  //   'if' '(' Expression ')' Statement ('else' Statement)?
  //PrintF("----------- new if\n");

  Expect(Token::IF, CHECK_OK);
  Expect(Token::LPAREN, CHECK_OK);
  Expression* condition = ParseExpression(true, CHECK_OK);
  Expect(Token::RPAREN, CHECK_OK);
  Statement* then_statement = ParseStatements(labels, Token::IF, CHECK_OK);
  Statement* else_statement = NULL;
  
  //bool default_seen = false;
  //ZoneListWrapper<Expression> if_conditions = factory()->NewList<Expression>(14);
  //ZoneListWrapper<Statement> if_statements = factory()->NewList<Statement>(14);
  List<Expression*> if_conditions(14);
  List<Statement*> if_statements(14);
  if_conditions.Add(condition);
  if_statements.Add(then_statement);

  while(peek() == Token::ELIF) {
    Next();
    Expect(Token::LPAREN, CHECK_OK);
    Expression* condition = ParseExpression(true, CHECK_OK);
    Expect(Token::RPAREN, CHECK_OK);
    Statement* then_statement = ParseStatements(labels, Token::IF, CHECK_OK);
    if_conditions.Add(condition);
    if_statements.Add(then_statement);
  }
  
  
  if (peek() == Token::ELSE) {
    Next();
    else_statement = ParseStatements(labels, Token::IF, CHECK_OK);
  } else if (!is_pre_parsing_) {
    else_statement = factory()->EmptyStatement();
  }
  Expect(Token::END, CHECK_OK); //Z:
  
  
  // Loop backward throught if condition/statement list to build the if's
  int i = if_conditions.length();
  IfStatement* if_head = NULL;
  while (--i >= 0) {
    //PrintF("---- i is %i \n", i);
    Expression* condition = if_conditions.at(i);
    Statement* then_statement = if_statements.at(i);
    if_head = NEW(IfStatement(condition, then_statement, else_statement));
    else_statement = if_head;  
  }
  
  return if_head;
  //return NEW(IfStatement(condition, then_statement, else_statement));
}

TryStatement* ZAstBuildingParser::ParseTryStatement(bool* ok) {
  // TryStatement ::
  //   'try' Block Catch
  //   'try' Block Finally
  //   'try' Block Catch Finally
  //
  // Catch ::
  //   'catch' '(' Identifier ')' Block
  //
  // Finally ::
  //   'finally' Block

  Expect(Token::TRY, CHECK_OK);

  ZoneList<BreakTarget*>* target_list = NEW(ZoneList<BreakTarget*>(0));
  TargetCollector collector(target_list);
  Block* try_block;

  { Target target(this, &collector);
    try_block = ParseStatements(NULL, Token::TRY, CHECK_OK); //Z:
  }

  Block* catch_block = NULL;
  VariableProxy* catch_var = NULL;
  Block* finally_block = NULL;

  Token::Value tok = peek();
  if (tok != Token::CATCH && tok != Token::FINALLY) {
    ReportMessage("no_catch_or_finally", Vector<const char*>::empty());
    *ok = false;
    return NULL;
  }

  // If we can break out from the catch block and there is a finally block,
  // then we will need to collect jump targets from the catch block. Since
  // we don't know yet if there will be a finally block, we always collect
  // the jump targets.
  ZoneList<BreakTarget*>* catch_target_list = NEW(ZoneList<BreakTarget*>(0));
  TargetCollector catch_collector(catch_target_list);
  bool has_catch = false;
  if (tok == Token::CATCH) {
    has_catch = true;
    Consume(Token::CATCH);

    Expect(Token::LPAREN, CHECK_OK);
    Handle<String> name = ParseIdentifier(CHECK_OK);
    Expect(Token::RPAREN, CHECK_OK);

    // Z: comment out the brackes
    //if (peek() == Token::LBRACE) {  
      // Allocate a temporary for holding the finally state while
      // executing the finally block.
      catch_var = top_scope_->NewTemporary(Factory::catch_var_symbol());
      Literal* name_literal = NEW(Literal(name));
      Expression* obj = NEW(CatchExtensionObject(name_literal, catch_var));
      { Target target(this, &catch_collector);
        catch_block = WithHelper(obj, NULL, true, CHECK_OK);
      }
    //} else {
      //Expect(Token::LBRACE, CHECK_OK);
    //}

    tok = peek();
  }

  if (tok == Token::FINALLY || !has_catch) {
    Consume(Token::FINALLY);
    // Declare a variable for holding the finally state while
    // executing the finally block.
    finally_block = ParseStatements(NULL, Token::TRY, CHECK_OK); //Z:
  }
  
  Expect(Token::END, CHECK_OK); //Z:

  // Simplify the AST nodes by converting:
  //   'try { } catch { } finally { }'
  // to:
  //   'try { try { } catch { } } finally { }'

  if (!is_pre_parsing_ && catch_block != NULL && finally_block != NULL) {
    TryCatch* statement = NEW(TryCatch(try_block, catch_var, catch_block));
    statement->set_escaping_targets(collector.targets());
    try_block = NEW(Block(NULL, 1, false));
    try_block->AddStatement(statement);
    catch_block = NULL;
  }

  TryStatement* result = NULL;
  if (!is_pre_parsing_) {
    if (catch_block != NULL) {
      ASSERT(finally_block == NULL);
      result = NEW(TryCatch(try_block, catch_var, catch_block));
      result->set_escaping_targets(collector.targets());
    } else {
      ASSERT(finally_block != NULL);
      result = NEW(TryFinally(try_block, finally_block));
      // Add the jump targets of the try block and the catch block.
      for (int i = 0; i < collector.targets()->length(); i++) {
        catch_collector.targets()->Add(collector.targets()->at(i));
      }
      result->set_escaping_targets(catch_collector.targets());
    }
  }

  return result;
}


Block* ZAstBuildingParser::WithHelper(Expression* obj,
                          ZoneStringList* labels,
                          bool is_catch_block,
                          bool* ok) {
  // Parse the statement and collect escaping labels.
  ZoneList<BreakTarget*>* target_list = NEW(ZoneList<BreakTarget*>(0));
  TargetCollector collector(target_list);
  Statement* stat;
  { Target target(this, &collector);
    with_nesting_level_++;
    top_scope_->RecordWithStatement();
    //stat = ParseStatement(labels, CHECK_OK);
    stat = ParseStatements(labels, Token::TRY, CHECK_OK); //Z:
    with_nesting_level_--;
  }
  // Create resulting block with two statements.
  // 1: Evaluate the with expression.
  // 2: The try-finally block evaluating the body.
  Block* result = NEW(Block(NULL, 2, false));

  if (result != NULL) {
    result->AddStatement(NEW(WithEnterStatement(obj, is_catch_block)));

    // Create body block.
    Block* body = NEW(Block(NULL, 1, false));
    body->AddStatement(stat);

    // Create exit block.
    Block* exit = NEW(Block(NULL, 1, false));
    exit->AddStatement(NEW(WithExitStatement()));

    // Return a try-finally statement.
    TryFinally* wrapper = NEW(TryFinally(body, exit));
    wrapper->set_escaping_targets(collector.targets());
    result->AddStatement(wrapper);
  }
  return result;
}


CaseClause* ZAstBuildingParser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
  // CaseClause ::
  //   'case' Expression ':' Statement*
  //   'default' ':' Statement*

  Expression* label = NULL;  // NULL expression indicates default case
  if (peek() == Token::CASE) {
    Expect(Token::CASE, CHECK_OK);
    label = ParseExpression(true, CHECK_OK);
  } else {
    Expect(Token::DEFAULT, CHECK_OK);
    if (*default_seen_ptr) {
      ReportMessage("multiple_defaults_in_switch",
                    Vector<const char*>::empty());
      *ok = false;
      return NULL;
    }
    *default_seen_ptr = true;
  }
  Expect(Token::COLON, CHECK_OK);

  ZoneListWrapper<Statement> statements = factory()->NewList<Statement>(5);
  while (peek() != Token::CASE &&
         peek() != Token::DEFAULT &&
         peek() != Token::END) {
    Statement* stat = ParseStatement(NULL, CHECK_OK);
    statements.Add(stat);
  }

  return NEW(CaseClause(label, statements.elements()));
}


SwitchStatement* ZAstBuildingParser::ParseSwitchStatement(ZoneStringList* labels,
                                              bool* ok) {
  // SwitchStatement ::
  //   'switch' '(' Expression ')' '{' CaseClause* '}'

  SwitchStatement* statement = NEW(SwitchStatement(labels));
  Target target(this, statement);

  Expect(Token::SWITCH, CHECK_OK);
  Expect(Token::LPAREN, CHECK_OK);
  Expression* tag = ParseExpression(true, CHECK_OK);
  Expect(Token::RPAREN, CHECK_OK);

  bool default_seen = false;
  ZoneListWrapper<CaseClause> cases = factory()->NewList<CaseClause>(4);
  // Expect(Token::LBRACE, CHECK_OK);
  while (peek() != Token::END) {
    CaseClause* clause = ParseCaseClause(&default_seen, CHECK_OK);
    cases.Add(clause);
  }
  Expect(Token::END, CHECK_OK);

  if (statement) statement->Initialize(tag, cases.elements());
  return statement;
}


FunctionLiteral* ZAstBuildingParser::ParseFunctionLiteral(Handle<String> var_name,
                                              int function_token_position,
                                              FunctionLiteralType type,
                                              bool* ok) {
  // Function ::
  //   '(' FormalParameterList? ')' '{' FunctionBody '}'

  bool is_named = !var_name.is_null();

  // The name associated with this function. If it's a function expression,
  // this is the actual function name, otherwise this is the name of the
  // variable declared and initialized with the function (expression). In
  // that case, we don't have a function name (it's empty).
  Handle<String> name = is_named ? var_name : factory()->EmptySymbol();
  // The function name, if any.
  Handle<String> function_name = factory()->EmptySymbol();
  if (is_named && (type == EXPRESSION || type == NESTED)) {
    function_name = name;
  }

  int num_parameters = 0;
  // Parse function body.
  { Scope::Type type = Scope::FUNCTION_SCOPE;
    Scope* scope = factory()->NewScope(top_scope_, type, inside_with());
    LexicalScope lexical_scope(this, scope);
    TemporaryScope temp_scope(this);
    top_scope_->SetScopeName(name);

    //  FormalParameterList ::
    //    '(' (Identifier)*[','] ')'
    Expect(Token::LPAREN, CHECK_OK);
    int start_pos = scanner_.location().beg_pos;
    bool done = (peek() == Token::RPAREN);
    while (!done) {
      Handle<String> param_name = ParseIdentifier(CHECK_OK);
      if (!is_pre_parsing_) {
        top_scope_->AddParameter(top_scope_->DeclareLocal(param_name,
                                                          Variable::VAR));
        num_parameters++;
      }
      done = (peek() == Token::RPAREN);
      if (!done) Expect(Token::COMMA, CHECK_OK);
    }
    Expect(Token::RPAREN, CHECK_OK);

    //Expect(Token::LBRACE, CHECK_OK);
    ZoneListWrapper<Statement> body = factory()->NewList<Statement>(8);

    // If we have a named function expression, we add a local variable
    // declaration to the body of the function with the name of the
    // function and let it refer to the function itself (closure).
    // NOTE: We create a proxy and resolve it here so that in the
    // future we can change the AST to only refer to VariableProxies
    // instead of Variables and Proxis as is the case now.
    if (!function_name.is_null() && function_name->length() > 0) {
      Variable* fvar = top_scope_->DeclareFunctionVar(function_name);
      VariableProxy* fproxy =
          top_scope_->NewUnresolved(function_name, inside_with());
      fproxy->BindTo(fvar);
      body.Add(new ExpressionStatement(
                   new Assignment(Token::INIT_VAR, fproxy,
                                  NEW(ThisFunction()),
                                  RelocInfo::kNoPosition)));
    }

    // Determine if the function will be lazily compiled. The mode can
    // only be PARSE_LAZILY if the --lazy flag is true.
    bool is_lazily_compiled =
        mode() == PARSE_LAZILY && top_scope_->HasTrivialOuterContext();

    int materialized_literal_count;
    int expected_property_count;
    bool contains_array_literal;
    bool only_this_property_assignments;
    bool only_simple_this_property_assignments;
    Handle<FixedArray> this_property_assignments;
    if (is_lazily_compiled && pre_data() != NULL) {
      FunctionEntry entry = pre_data()->GetFunctionEnd(start_pos);
      int end_pos = entry.end_pos();
      Counters::total_preparse_skipped.Increment(end_pos - start_pos);
      scanner_.SeekForward(end_pos);
      materialized_literal_count = entry.literal_count();
      expected_property_count = entry.property_count();
      only_this_property_assignments = false;
      only_simple_this_property_assignments = false;
      this_property_assignments = Factory::empty_fixed_array();
      contains_array_literal = entry.contains_array_literal();
    } else {
      ParseSourceElements(&body, Token::END, CHECK_OK);
      materialized_literal_count = temp_scope.materialized_literal_count();
      expected_property_count = temp_scope.expected_property_count();
      contains_array_literal = temp_scope.contains_array_literal();
      only_this_property_assignments =
          temp_scope.only_this_property_assignments();
      only_simple_this_property_assignments =
          temp_scope.only_simple_this_property_assignments();
      this_property_assignments = temp_scope.this_property_assignments();
    }

    Expect(Token::END, CHECK_OK);
    int end_pos = scanner_.location().end_pos;

    FunctionEntry entry = log()->LogFunction(start_pos);
    if (entry.is_valid()) {
      entry.set_end_pos(end_pos);
      entry.set_literal_count(materialized_literal_count);
      entry.set_property_count(expected_property_count);
      entry.set_contains_array_literal(contains_array_literal);
    }

    FunctionLiteral* function_literal =
        NEW(FunctionLiteral(name,
                            top_scope_,
                            body.elements(),
                            materialized_literal_count,
                            contains_array_literal,
                            expected_property_count,
                            only_this_property_assignments,
                            only_simple_this_property_assignments,
                            this_property_assignments,
                            num_parameters,
                            start_pos,
                            end_pos,
                            function_name->length() > 0));
    if (!is_pre_parsing_) {
      function_literal->set_function_token_position(function_token_position);
    }
    return function_literal;
  }
}


Statement* ZAstBuildingParser::ParseForStatement(ZoneStringList* labels, bool* ok) {
  // ForStatement ::
  //   'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement

  Statement* init = NULL;

  Expect(Token::FOR, CHECK_OK);
  Expect(Token::LPAREN, CHECK_OK);
  if (peek() != Token::SEMICOLON) {
    if (peek() == Token::VAR || peek() == Token::CONST) {
      Expression* each = NULL;
      Block* variable_statement =
          ParseVariableDeclarations(false, &each, CHECK_OK);
      if (peek() == Token::IN && each != NULL) {
        ForInStatement* loop = NEW(ForInStatement(labels));
        Target target(this, loop);

        Expect(Token::IN, CHECK_OK);
        Expression* enumerable = ParseExpression(true, CHECK_OK);
        Expect(Token::RPAREN, CHECK_OK);

        Statement* body = ParseStatements(NULL, CHECK_OK); //Z:
        Expect(Token::END, CHECK_OK);
        if (is_pre_parsing_) {
          return NULL;
        } else {
          loop->Initialize(each, enumerable, body);
          Block* result = NEW(Block(NULL, 2, false));
          result->AddStatement(variable_statement);
          result->AddStatement(loop);
          // Parsed for-in loop w/ variable/const declaration.
          return result;
        }

      } else {
        init = variable_statement;
      }

    } else {
      Expression* expression = ParseExpression(false, CHECK_OK);
      if (peek() == Token::IN) {
        // Report syntax error if the expression is an invalid
        // left-hand side expression.
        if (expression == NULL || !expression->IsValidLeftHandSide()) {
          if (expression != NULL && expression->AsCall() != NULL) {
            // According to ECMA-262 host function calls are permitted to
            // return references.  This cannot happen in our system so we
            // will always get an error.  We could report this as a syntax
            // error here but for compatibility with KJS and SpiderMonkey we
            // choose to report the error at runtime.
            Handle<String> type = Factory::invalid_lhs_in_for_in_symbol();
            expression = NewThrowReferenceError(type);
          } else {
            // Invalid left hand side expressions that are not function
            // calls are reported as syntax errors at compile time.
            ReportMessage("invalid_lhs_in_for_in",
                          Vector<const char*>::empty());
            *ok = false;
            return NULL;
          }
        }
        ForInStatement* loop = NEW(ForInStatement(labels));
        Target target(this, loop);

        Expect(Token::IN, CHECK_OK);
        Expression* enumerable = ParseExpression(true, CHECK_OK);
        Expect(Token::RPAREN, CHECK_OK);

        Statement* body = ParseStatements(NULL, CHECK_OK); //Z:
        Expect(Token::END, CHECK_OK);
        if (loop) loop->Initialize(expression, enumerable, body);

        // Parsed for-in loop.
        return loop;

      } else {
        init = NEW(ExpressionStatement(expression));
      }
    }
  }

  // Standard 'for' loop
  LoopStatement* loop = NEW(LoopStatement(labels, LoopStatement::FOR_LOOP));
  Target target(this, loop);

  // Parsed initializer at this point.
  Expect(Token::SEMICOLON, CHECK_OK);

  Expression* cond = NULL;
  if (peek() != Token::SEMICOLON) {
    cond = ParseExpression(true, CHECK_OK);
  }
  Expect(Token::SEMICOLON, CHECK_OK);

  Statement* next = NULL;
  if (peek() != Token::RPAREN) {
    Expression* exp = ParseExpression(true, CHECK_OK);
    next = NEW(ExpressionStatement(exp));
  }
  Expect(Token::RPAREN, CHECK_OK);

  Statement* body = ParseStatements(NULL, CHECK_OK); //Z:
  Expect(Token::END, CHECK_OK);

  if (loop) loop->Initialize(init, cond, next, body);
  return loop;
}

/*
// do block becomes {} - fairly useless until lexical scoping
Block* ZAstBuildingParser::ParseBlock(ZoneStringList* labels, bool* ok) {
  // Block ::
  //   '{' Statement* '}'

  // Note that a Block does not introduce a new execution scope!
  // (ECMA-262, 3rd, 12.2)
  //
  // Construct block expecting 16 statements.
  Block* result = NEW(Block(labels, 16, false));
  Target target(this, result);
  //Expect(Token::LBRACE, CHECK_OK);
  Expect(Token::DO, CHECK_OK);  //Z:
  while (peek() != Token::END) {
    Statement* stat = ParseStatement(NULL, CHECK_OK);
    if (stat && !stat->IsEmpty()) result->AddStatement(stat);
  }
  Expect(Token::END, CHECK_OK);
  return result;
}
*/

Statement* ZAstBuildingParser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
  Expect(Token::WITH, CHECK_OK);
  ReportMessage("*** with statement considered harmful (update messages.js to remove 'unknown message') ***",
                 Vector<const char*>::empty());
  //ReportUnexpectedToken(Token::WITH);
  *ok = false;
  return NULL;
}






